package com.repair.payment.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.repair.api.pay.request.PayQueryPageRequest;
import com.repair.api.pay.request.PayQueryRequest;
import com.repair.api.pay.request.PayRefundRequest;
import com.repair.api.pay.request.condition.PayNumQueryCondition;
import com.repair.api.pay.request.param.PayQueryParam;
import com.repair.api.pay.response.PayQueryResponse;
import com.repair.api.pay.response.PayRefundResponse;
import com.repair.api.pay.response.vo.PaymentInfoVO;
import com.repair.base.exception.BizException;
import com.repair.base.response.PageResponse;
import com.repair.base.utils.DateToLocalDateTimeUtil;
import com.repair.base.utils.ResponseCode;
import com.repair.payment.exception.RefundErrorCode;
import com.repair.payment.exception.RefundException;
import com.repair.payment.mapper.PaymentRefundMapper;
import com.repair.payment.pojo.convertor.PaymentRefundConvertor;
import com.repair.payment.pojo.entity.PaymentRefund;
import com.repair.payment.service.PaymentRefundService;
import com.repair.satoken.utils.StpKit;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;

import static com.repair.pay.config.AliPayConfig.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 郑春雨
 * @since 2024-10-18
 */
@Service
public class PaymentRefundServiceImpl extends ServiceImpl<PaymentRefundMapper, PaymentRefund> implements PaymentRefundService {

    @Override
    public PayRefundResponse<Boolean> refund(PayRefundRequest payRefundRequest) {
        String payOrderNum = payRefundRequest.getPayOrderNum();
        BigDecimal orderPrice = payRefundRequest.getOrderPrice();
        String orderNum = payRefundRequest.getOrderNum();
        PaymentRefund paymentRefund = baseMapper.selectOne(new QueryWrapper<PaymentRefund>().eq("pay_order_num", payOrderNum));
        // 检查是否已经退款，幂等
        if (paymentRefund != null) {
            throw new BizException(RefundErrorCode.REFUND_REPEAT);
        }
        alipayRefund(orderNum, payOrderNum, orderPrice);
        return createResponse(true);
    }

    @Override
    public PageResponse<PaymentInfoVO> queryRefundPayList(PayQueryPageRequest<PayQueryParam> request) {
        Page<PaymentRefund> page = new Page<>();
        page.setCurrent(request.getCurrentPage());
        page.setSize(request.getPageSize());
        PayQueryParam param = request.getData();
        QueryWrapper<PaymentRefund> wrapper = new QueryWrapper<>();
        if (param != null) {
            wrapper.like(StringUtils.hasText(param.getOrderNum()), "order_num", param.getOrderNum())
                    .like(StringUtils.hasText(param.getMethod()), "method", param.getMethod())
                    .like(param.getPayerId() != null, "payer_id", param.getPayerId())
                    .like(StringUtils.hasText(param.getAccount()), "account", param.getAccount())
                    .like(StringUtils.hasText(param.getPayOrderNum()), "pay_order_num", param.getPayOrderNum())
                    .between(param.getSucceedTimeMin() != null && param.getSucceedTimeMax() != null, "succeed_time", param.getSucceedTimeMin(), param.getSucceedTimeMax())
                    .between(param.getPriceMin() != null && param.getPriceMax() != null, "price", param.getPriceMin(), param.getPriceMax());
        }
        wrapper.orderByDesc("create_time");
        Page<PaymentRefund> selectPage = baseMapper.selectPage(page, wrapper);
        PageResponse<PaymentInfoVO> response = new PageResponse<>();
        response.setData(PaymentRefundConvertor.INSTANCE.mapToVOList(selectPage.getRecords()));
        response.setTotal((int) selectPage.getTotal());
        response.setPageSize(request.getPageSize());
        response.setCurrentPage(request.getCurrentPage());
        response.setPageTotal((int) selectPage.getPages());
        response.setSuccess(true);
        return response;
    }

    @Override
    public PayQueryResponse<PaymentInfoVO> getPaymentDetail(PayQueryRequest request) {
        QueryWrapper<PaymentRefund> wrapper = null;
        if (request.getPayCondition() instanceof PayNumQueryCondition) {
            PayNumQueryCondition queryCondition = (PayNumQueryCondition) request.getPayCondition();
            wrapper = new QueryWrapper<PaymentRefund>()
                    .eq("pay_order_num", queryCondition.getPayOrderNum());
        }
        PaymentRefund paymentRefund = baseMapper.selectOne(wrapper);
        if (paymentRefund == null) {
            throw new BizException(ResponseCode.SELECT_FAILED);
        }
        PayQueryResponse<PaymentInfoVO> response = new PayQueryResponse<>();
        response.setData(PaymentRefundConvertor.INSTANCE.mapToVO(paymentRefund));
        response.setSuccess(true);
        return response;
    }

    private PayRefundResponse<Boolean> createResponse(boolean success) {
        PayRefundResponse<Boolean> response = new PayRefundResponse<>();
        response.setSuccess(success);
        response.setData(success);
        return response;
    }


    private void alipayRefund(String orderNum, String payOrderNum, BigDecimal orderPrice) {
        Long userId = Long.valueOf((String) StpKit.USER.getLoginId());
        AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, APP_ID,
                APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();

        JSONObject bizContent = new JSONObject();
        bizContent.put("trade_no", payOrderNum);
        bizContent.put("refund_amount", orderPrice);
        bizContent.put("out_request_no", orderNum);
        bizContent.put("body", "支付超时");


        request.setBizContent(bizContent.toString());
        try {
            AlipayTradeRefundResponse response = alipayClient.execute(request);

            if (response.isSuccess()) {
                log.debug("退款成功");
                PaymentRefund paymentRefund = new PaymentRefund();
                paymentRefund.setOrderNum(orderNum);
                paymentRefund.setPrice(orderPrice);
                paymentRefund.setPayOrderNum(payOrderNum);
                LocalDateTime successTime = DateToLocalDateTimeUtil.convert(response.getGmtRefundPay());
                paymentRefund.setSucceedTime(successTime);
                paymentRefund.setAccount(response.getBuyerUserId());
                paymentRefund.setPayerId(userId);
                paymentRefund.setMethod("支付宝");

                int i = baseMapper.insert(paymentRefund);
                Assert.isTrue(i == 1, () -> new RuntimeException("插入退款记录失败"));
            } else {
                log.debug("退款失败");
                throw new RefundException(RefundErrorCode.REFUND_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RefundException(RefundErrorCode.REFUND_ERROR);
        }

    }

}
